/** 
 * 电视剧控制器模块
 */
module controller.TeleplayController;

import std.conv : to;
import std.algorithm.searching : canFind;

import vibe.http.server : HTTPServerRequest, HTTPServerResponse;
import vibe.data.json : Json, serializeToJsonString;

import model.Teleplay;
import model.TeleplayVlink;
import repository.TeleplayRepo;

import utils.RespData : RespData;
import utils.ObjMapping : ObjMapping;
import utils.DataCache;
import utils.CacheKey : CacheKey;
import utils.SecurityVerification : signValidator;

// import std.stdio;

/** 
 * 临时处理数据的类
 */
class Obj
{
    uint year;
    TeleplayDto[] list;

    this (uint year, TeleplayDto[] list)
    {
        this.year = year;
        this.list = list;
    }
}

TeleplayRepo _tRepo; // Teleplay仓储

static this ()
{
    // 注入Teleplay仓储
    _tRepo = new TeleplayRepo();
}

static ~this ()
{
    destroy(_tRepo);
}

/** 
* 获取全部电视剧（年份分组）
*/
void getAllTeleplayList (HTTPServerRequest req, HTTPServerResponse resp)
{
    // 缓存中有数据直接取出返回
    auto data = cacheData.get(CacheKey.TELEPLAY_GLIST_CACHE);
    if (!data.isNull)
    {
        resp.writeJsonBody(RespData.newData(200, "ok", data.get));
        return;
    }

    Teleplay[] teleplayList = _tRepo.getTeleplayList();
    alias DtoList = TeleplayDto[];
    DtoList[uint] mylist;
    foreach (t; teleplayList)
    {
        mylist[t.year] ~= ObjMapping.mappingToObject!(TeleplayDto, Teleplay)(t);
    }

    Obj[] objList;
    foreach (key, value; mylist)
    {
        objList ~= new Obj(key, value);
    }

    // 设置缓存
    string jsonList = serializeToJsonString(objList);
    cacheData.put(CacheKey.TELEPLAY_GLIST_CACHE, jsonList);

    resp.writeJsonBody(RespData.newData(200, "ok", jsonList));
}

/** 
* 获取全部电视剧（不分组）
*/
public void getAllTeleplay (HTTPServerRequest req, HTTPServerResponse resp)
{
    // 后台管理请求不走缓存
    if ("X-Admin-Req" !in req.headers)
    {
        // 缓存中有数据直接取出返回
        auto data = cacheData.get(CacheKey.TELEPLAY_ALIST_CACHE);
        if (!data.isNull)
        {
            resp.writeJsonBody(RespData.newData(200, "ok", data.get));
            return;
        }
    }

    Teleplay[] teleplayList = _tRepo.getTeleplayList();
    TeleplayDto[] teleplayDtoList = [];
    foreach (t; teleplayList)
    {
        teleplayDtoList ~= ObjMapping.mappingToObject!(TeleplayDto, Teleplay)(t);
    }

    // 设置缓存
    string jsonList = serializeToJsonString(teleplayDtoList);
    cacheData.put(CacheKey.TELEPLAY_ALIST_CACHE, jsonList);

    resp.writeJsonBody(RespData.newData(200, "ok", jsonList));
}

/** 
* 分页获取电视剧列表数据
*/
void getTeleplayListPaging (HTTPServerRequest req, HTTPServerResponse resp)
{
    import std.string : format;

    string pageSizeStr = req.query.get("pageSize", "");
    string pageNumStr = req.query.get("pageNum", "");
    if (pageSizeStr == "" || pageNumStr == "")
    {
        resp.writeJsonBody(RespData.newData(400, "错误的请求"));
        return;
    }
    uint pageSize = to!uint(pageSizeStr);
    uint pageNum = to!uint(pageNumStr);

    string dataCacheKey = format("%s%s%s", CacheKey.TELEPLAY_PLIST_CACHE, pageSize, pageNum);
    string totalPageCacheKey = format("%s%s%s", CacheKey.TELEPLAY_TOTALPAGE_CACHE, pageSize, pageNum);

    // 缓存中有数据直接取出返回
    auto data = cacheData.get(dataCacheKey);
    auto totalPageStr = cacheData.get(totalPageCacheKey);
    if (!data.isNull && !totalPageStr.isNull)
    {
        int totalPage = to!int(totalPageStr.get);
        Json respData = RespData.newData(200, "ok", data.get);
        respData["totalPage"] = totalPage;
        resp.writeJsonBody(respData);
        return;
    }

    Teleplay[] teleplayList = _tRepo.getTeleplayListPaging(pageSize, pageNum);
    alias DtoList = TeleplayDto[];
    DtoList[uint] mylist;
    foreach (t; teleplayList)
    {
        mylist[t.year] ~= ObjMapping.mappingToObject!(TeleplayDto, Teleplay)(t);
    }

    Obj[] objList;
    foreach (key, value; mylist)
    {
        objList ~= new Obj(key, value);
    }

    uint total = _tRepo.getTotalCount();
    uint totalPage = (total + pageSize - 1) / pageSize;
    if (totalPage == 0)
    {
        totalPage = 1;
    }

    // 设置缓存
    string jsonList = serializeToJsonString(objList);
    cacheData.put(dataCacheKey, jsonList);
    cacheData.put(totalPageCacheKey, to!string(totalPage));

    auto respData = RespData.newData(200, "ok", jsonList);
    respData["totalPage"] = totalPage;
    resp.writeJsonBody(respData);
}

/** 
* 获取一个电视剧
*/
public void getOneTeleplay (HTTPServerRequest req, HTTPServerResponse resp)
{
    string id = req.params.get("id", "");
    if (id == "")
    {
        resp.writeJsonBody(RespData.newData(400, "错误的请求"));
        return;
    }

    Teleplay teleplay = _tRepo.getOneTeleplay(id);
    if (teleplay is null)
    {
        resp.writeJsonBody(RespData.newData(404, "未找到"));
        return;
    }

    Json respData = RespData.newData!(TeleplayDto)(200, "ok", ObjMapping.mappingToObject!(TeleplayDto, Teleplay)(
            teleplay));
    resp.writeJsonBody(respData);
}

/** 
* 获取电视剧集数列表
*/
void getTeleplayVlinks (HTTPServerRequest req, HTTPServerResponse resp)
{
    string id = req.query.get("tid", "");
    if (id == "")
    {
        resp.writeJsonBody(RespData.newData(400, "错误的请求"));
        return;
    }

    // 后台管理请求不走缓存
    if ("X-Admin-Req" !in req.headers)
    {
        // 缓存中有数据直接取出返回
        auto data = cacheData.get(CacheKey.TELEPLAY_VLIST_CACHE ~ id);
        if (!data.isNull)
        {
            resp.writeJsonBody(RespData.newData(200, "ok", data.get));
            return;
        }
    }

    TeleplayVlink[] list = _tRepo.getTeleplayVideoLinks(id);
    TeleplayVlinkDto[] dtoList = [];
    foreach (tl; list)
    {
        dtoList ~= ObjMapping.mappingToObject!(TeleplayVlinkDto, TeleplayVlink)(tl);
    }

    // 设置缓存
    string jsonList = serializeToJsonString(dtoList);
    cacheData.put(CacheKey.TELEPLAY_VLIST_CACHE ~ id, jsonList);

    resp.writeJsonBody(RespData.newData(200, "ok", jsonList));
}

/** 
* 获取所有电视剧年份
*/
void getTeleplayYears (HTTPServerRequest req, HTTPServerResponse resp)
{
    // 缓存中有数据直接取出返回
    auto data = cacheData.get(CacheKey.TELEPLAY_ALLYEAR_CACHE);
    if (!data.isNull)
    {
        resp.writeJsonBody(RespData.newData(200, "ok", data.get));
        return;
    }

    uint[] years = _tRepo.getTeleplayYears();

    // 设置缓存
    string jsonList = serializeToJsonString(years);
    cacheData.put(CacheKey.TELEPLAY_ALLYEAR_CACHE, jsonList);

    resp.writeJsonBody(RespData.newData(200, "ok", jsonList));
}

// 后台接口函数，需进行token校验--------------------------------------------

/** 
* 添加电视剧
*/
void addTeleplay (HTTPServerRequest req, HTTPServerResponse resp)
{
    import std.digest : toHexString;
    import std.digest.md : md5Of;

    Json json = req.json;
    string name = json["name"].to!string();
    string url = json["url"].to!string();
    string img = json["img"].to!string();
    string category = json["category"].to!string();
    string region = json["region"].to!string();
    uint year = json["year"].to!uint();
    string actors = json["actors"].to!string();
    string director = json["director"].to!string();
    string intro = json["intro"].to!string();
    string comment = json["comment"].to!string();
    string id = to!string(toHexString(md5Of(name)));

    string sign = json["sign"].to!string();

    import std.format : format;

    string reqParamsStr = format("%s%s%s%s", name, url, category, year);
    if (!signValidator(reqParamsStr, sign))
    {
        resp.writeJsonBody(RespData.newData(403, "签名不正确！"), 403);
        return;
    }

    TeleplayDtoFromCreate t = new TeleplayDtoFromCreate(id, name, url, category, region, year, actors, director, intro, img, comment);
    bool res = _tRepo.addTeleplay(ObjMapping.mappingToObject!(Teleplay, TeleplayDtoFromCreate)(
            t));
    if (!res)
    {
        resp.writeJsonBody(RespData.newData(500, "error"), 500);
        return;
    }
    resp.writeJsonBody(RespData.newData(200, "ok"), 201);
}

/** 
* 编辑电视剧
*/
void editTeleplay (HTTPServerRequest req, HTTPServerResponse resp)
{
    string id = req.params.get("id", "");
    if (id == "")
    {
        resp.writeJsonBody(RespData.newData(400, "错误的请求"), 400);
        return;
    }

    Json json = req.json;
    string name = json["name"].to!string();
    string url = json["url"].to!string();
    string img = json["img"].to!string();
    string category = json["category"].to!string();
    string region = json["region"].to!string();
    uint year = json["year"].to!uint();
    string actors = json["actors"].to!string();
    string director = json["director"].to!string();
    string intro = json["intro"].to!string();
    string comment = json["comment"].to!string();

    string sign = json["sign"].to!string();

    import std.format : format;

    string reqParamsStr = format("%s%s%s%s", name, url, category, year);
    if (!signValidator(reqParamsStr, sign))
    {
        resp.writeJsonBody(RespData.newData(403, "签名不正确！"), 403);
        return;
    }

    TeleplayDtoFromUpdate t = new TeleplayDtoFromUpdate(name, url, category, region, year, actors, director, intro, img, comment);
    bool res = _tRepo.updateTeleplay(id, ObjMapping.mappingToObject!(Teleplay, TeleplayDtoFromUpdate)(
            t));
    if (!res)
    {
        resp.writeJsonBody(RespData.newData(500, "error"), 500);
        return;
    }
    resp.writeJsonBody(RespData.newData(200, "ok"));
}

/** 
 * 删除电视剧
 */
void deleteTeleplay (HTTPServerRequest req, HTTPServerResponse resp)
{
    string id = req.params.get("id", "");
    string sign = req.query.get("sign", "");
    if (id == "" || sign == "")
    {
        resp.writeJsonBody(RespData.newData(400, "错误的请求"), 400);
        return;
    }
    if (!signValidator(id, sign))
    {
        resp.writeJsonBody(RespData.newData(403, "签名不正确！"), 403);
        return;
    }

    bool res = _tRepo.removeTeleplay(id);
    if (!res)
    {
        resp.writeJsonBody(RespData.newData(500, "error"), 500);
        return;
    }
    resp.writeJsonBody(RespData.newData(200, "ok"));
}

/** 
 * 写电视剧评语
 */
void doTeleplayComment (HTTPServerRequest req, HTTPServerResponse resp)
{
    string id = req.params.get("id", "");
    if (id == "")
    {
        resp.writeJsonBody(RespData.newData(400, "错误的请求"), 400);
        return;
    }

    Json json = req.json;
    string comment = json["comment"].to!string();
    if (comment == "")
    {
        resp.writeJsonBody(RespData.newData(400, "请输入评语"), 400);
        return;
    }

    bool res = _tRepo.doComment(id, comment);
    if (!res)
    {
        resp.writeJsonBody(RespData.newData(500, "error"), 500);
        return;
    }
    resp.writeJsonBody(RespData.newData(200, "ok"));
}
// end后台接口函数，需进行token校验--------------------------------------------
